15.3 Zeichenketten schreiben und Fonts 

Java kann Zeichenketten in verschiedenen Zeichensätzen (engl. fonts) auf die Zeichenfläche bringen. Zum Zeichnen gibt es unterschiedliche Methoden, von denen in jeder Java-Version Varianten und Klassen hinzukamen. Nicht viel besser ist es mit den Font-Informationen; auch dafür gibt es verwirrend viele Möglichkeiten zur Repräsentation der Meta-Daten.
15.3.1 Zeichenfolgen schreiben 

Zum Zeichnen heißt die wichtigste Funktion drawString(). Ihre drei Parameter beschreiben die zu schreibende Zeichenkette sowie die x- und y-Koordinate. Die Koordinaten bestimmen die Position der Schriftlinie – auch Grundlinie, engl. baseline, genannt –, auf der die Buchstaben stehen.
abstract class java.awt.Graphics |
- abstract void drawString( String s, int x, int y ) Schreibt einen String in der aktuellen Farbe und dem aktuellen Zeichensatz.
- abstract void drawString( AttributedCharacterIterator iterator, int x, int y ) Schreibt einen String, der durch den Attribut-Iterator gegeben ist.
- abstract void drawChars( char[] data, int offset, int length, int x, int y ) Schreibt die Zeichenkette und bezieht die Daten aus einem Char-Feld.
- abstract void drawBytes( byte[] data, int offset, int length, int x, int y ) Schreibt die Zeichenkette und bezieht die Daten aus einem Byte-Feld.
15.3.2 Die Font-Klasse 

Die Funktion drawString() verwendet immer den aktuellen Zeichensatz. Um diesen zu ändern, benutzen wir auf dem aktuellen Graphics-Objekt die Funktion setFont(). Der Übergabeparameter ist ein Font-Objekt, das wir von woanders erfragen oder vorher erzeugen müssen. Der Konstruktor von Font ist durch verschiedene Parameter definiert.
class java.awt.Font implements Serializable |
- Font( String name, int style, int size ) Erzeugt ein Font-Objekt mit einem gegebenen Namen, Stil und Größe. Für den Stil deklariert die Font-Klasse drei symbolische Konstanten: Font.PLAIN, Font.ITALIC und Font.BOLD. Die Stil-Attribute können mit dem binären Oder oder dem arithmetischen Plus verbunden werden; ein fetter und kursiver Zeichensatz erreicht Font.BOLD | Font.ITALIC (beziehungsweise Font.BOLD + Font.ITALIC). Die Größe ist in Punkt angegeben, wobei ein Punkt 1/72 Zoll (in etwa 0,376 mm) entspricht. Der Name des Zeichensatzes ist entweder physikalisch (zum Beispiel »Verdana« oder »Geneva«) oder logisch [Die Webseite http://java.sun.com/j2se/1.3/docs/guide/intl/fontprop.html beschreibt diese Umsetzung. ] , wobei für die logischen Kennzeichungen die Klasse Font die Konsanten DIALOG, DIALOG_INPUT, SANS_SERIF, SERIF und MONOSPACED deklariert.
| Beispiel Ein Font-Objekt erzeugen:
Häufig wird dieses Zeichensatz-Objekt sofort in setFont() genutzt, so wie: |
Ist im Programm der aktuell verwendete Zeichensatz nötig, können wir getFont() von der Graphics-Klasse verwenden:
abstract class java.awt.Graphics |
15.3.3 Einen neuen Font aus einem gegebenen Font ableiten 

Steht ein Font zur Verfügung. Soll ausgehend von diesem ein neues Font-Objekt mit einer kleinen Änderung etwa in der Größe oder im Attribut (fett, kursiv) hergestellt werden, so lassen sich die deriveFont()-Funktionen einsetzen.
Beispiel Ausgehend von einem existierenden Font-Objekt f soll ein neuer Font mit dem gleichen Zeichensatz und Stil abgeleitet werden, der jedoch 20 Punkt groß ist:
Font font = f.deriveFont( 20f ); Der Parameter ist vom Typ float, damit Verwechslungen mit deriveFont(int) – das liefert einen neuen Font in normal, fett und/oder kursiv – ausgeschlossen sind. |
class java.awt.Font implements Serializable |
- Font deriveFont( int style, float size ) Wie der Originalzeichensatz, nur mit einer neuen Größe und einem neuen Stil.
- Font deriveFont( AffineTransformation trans ) Erzeugt ein neues Font-Objekt, das über ein Transformationsobjekt modifiziert ist. Liefert ein neues Zeichensatzobjekt in der Größe von einem Punkt und keinem besonderen Stil.
15.3.4 Zeichensätze des Systems ermitteln 

Um herauszufinden, welche Zeichensätze auf einem System installiert sind, liefert getAvailableFontFamilyNames() auf einem GraphicsEnvironment ein Feld mit Font-Objekten. Ein Objekt vom Typ GraphicsEnvironment beschreibt die Zeichensätze des Systems und GraphicsDevice-Objekte. Ein GraphicsDevice ist eine Malfläche, also das, worauf das System zeichnen kann. Das kann der Bildschirm sein, aber auch ein Drucker oder eine Hintergrundgrafik. Die statische Fabrik-Funktion getLocalGraphicsEnvironment() liefert ein solches GraphicsEnvironment-Objekt.
Beispiel Im folgenden Codesegment gibt eine Schleife alle Zeichensatznamen aus:
for ( String fonts : GraphicsEnvironment.getLocalGraphicsEnvironment(). getAvailableFontFamilyNames() ) System.out.println( fonts ); Auf meinem System liefert die Schleife die folgenden Zeilen: Arial Arial Black Arial Narrow ... Wingdings Wingdings 2 Wingdings 3 |
abstract class java.awt.GraphicsEnvironment |
- static GraphicsEnvironment getLocalGraphicsEnvironment() Liefert das aktuelle GraphicsEnvironment-Objekt.
- abstract Font[] getAllFonts() Liefert ein Feld mit allen verfügbaren Font-Objekten in einer Größe von einem Punkt.
- abstract String[] getAvailableFontFamilyNames() Liefert ein Feld mit allen verfügbaren Zeichensatzfamilien.
- abstract String[] getAvailableFontFamilyNames( Locale l ) Liefert ein Feld mit verfügbaren Zeichensatzfamilien, die zu einer Sprache l gehören.
15.3.5 Neue TrueType-Fonts in Java nutzen 

Die auf allen Systemen vordefinierten Standardzeichensätze sind etwas dürftig, obwohl die Font-Klasse selbst jeden installierten Zeichensatz einlesen kann. Da ein Java-Programm aber nicht von der Existenz eines bestimmten Zeichensatzes ausgehen kann, ist es praktisch, einen Zeichensatz mit der Installation auszuliefern und dann diesen zu laden; das kann die Font-Klasse mit der statischen Funktion createFont(). Aus einem Eingabestrom liest die Methode den TrueType-Zeichensatz und erstellt das entsprechende Font-Objekt.
Listing 15.5 com/javatutor/insel/ui/graphics/TrueTypePanel.java, Ausschnitt
Font f = Font.createFont( Font.TRUETYPE_FONT, new FileInputStream("NASALIZA.TTF") );
Das erste Argument ist immer Font.TRUETYPE_FONT. Das zweite Argument bestimmt den Eingabestrom zur Binärdatei mit den Zeichensatzinformationen. Die Daten werden ausgelesen und zu einem Font-Objekt verarbeitet. Da die Daten intern über einen gepufferten Datenstrom in eine temporäre Datei geschrieben werden, ist eine eigene Pufferung über einen BufferedInputStream nur zusätzlicher Overhead.
Waren die Beschreibungsinformationen in der Datei ungültig, so erzeugt die Font-Klasse eine FontFormatException("Unable to create font - bad font data"). Dateifehler fallen hier nicht darunter und werden extra über eine IOException angezeigt. Der Datenstrom wird anschließend nicht wieder geschlossen.
An dieser Stelle verwundert es vielleicht, dass von der Arbeitsweise her die Methode createFont() der des Konstruktors ähnlich sein müsste, aber der Parameterliste die Attribute fehlen. Das liegt daran, dass die Methode automatisch einen Zeichensatz der Größe 1 im Stil Font.PLAIN erzeugt. Um einen größeren Zeichensatz zu erzeugen, müssen wir ein zweites Font-Objekt anlegen, was am einfachsten mit der Methode deriveFont() geschieht.
class java.awt.Font implements Serializable |
- static Font createFont( int fontFormat, InputStream fontStream ) throws FontFormatException, IOException Liefert ein neues Zeichensatzobjekt in der Größe von einem Punkt und mit keinem besonderen Stil.
15.3.6 Font-Metadaten durch FontMetrics 

Jedes Font-Objekt beinhaltet Informationen zur Schriftsatzfamilie, zum Schriftsatznamen sowie zu Größe und Stil. Was sie nicht bieten, sind Zugriff auf Metadaten, etwa auf Abmessungen des Zeichensatzes. Um diese Daten aufzuspüren, ist ein FontMetrics-Objekt nötig. Es verwaltet metrische Informationen, die mit einer Schriftart verbunden sind. Dazu gehören Ober- und Unterlänge, Schrifthöhe und Zeilenabstand.
Das FontMetric-Objekt lässt sich nicht direkt vom Font-Objekt erfragen – wie sinnig –, sondern mit getFontMetrics() der Graphics-Klasse. (Umgekehrt liefert aber getFont() aus FontMetrics das Font-Objekt, das diese Metriken beschreibt.)
In der paint()-Methode kann also mittels
FontMetrics fm = g.getFontMetrics();
auf die Metriken des aktuellen Zeichensatzes zugegriffen werden.
abstract class java.awt.Graphics |
Die Klasse FontMetrics bietet die folgenden Methoden an, wobei sich alle Angaben auf das jeweilige Zeichensatzobjekt beziehen. Beziehen sich die Rückgabeparameter auf die Zeichengröße, so erfolgt die Angabe immer in Pixel.
abstract class java.awt.FontMetrics implements Serializable |
- int bytesWidth( byte[] data, int off, int len ) Gibt die Breite aller Zeichen des Felds zurück. Beginnt bei off und liest len Zeichen.
- int stringWidth( String str ) Gibt die Breite der Zeichenkette zurück, wenn diese gezeichnet würde. Nutzt intern charsWidth().
- int getAscent() Gibt den Abstand von der Grundlinie zur oberen Grenze (Oberlänge) zurück. Ist standardmäßig getSize() vom Font-Objekt.
- int getDescent() Gibt den Abstand von der Grundlinie zur unteren Grenze (Unterlänge) zurück. Standardmäßig 0.
- int getLeading() Gibt den Durchschuss (engl. leading) zurück. Der Durchschuss ist der Standard-Abstand zwischen zwei Zeilen.
- int getHeight() Gibt den Standard-Zeilenabstand (Abstand zwischen Grundlinie und Grundlinie) in Pixel zurück. Er berechnet sich aus Durchschuss + Oberlänge + Unterlänge. In Quellcode ausgedrückt: getAscent() + getDescent() + getLeading().
- int getMaxAscent() Liefert das Maximum aller Oberlängen in Pixel. Einige Zeichen können sich oberhalb der Oberlänge bewegen. Die Standard-Implementierung leitet einfach nur an getAscent() weiter.
- int getMaxDescent() Liefert das Maximum aller Unterlängen in Pixel. Leitet standardmäßig an getDescent() weiter.
- int[] getWidths() Liefert in einem Ganzzahlfeld die Breiten – ermittelt durch charWidth() – der ersten 256 Zeichen zurück.
Hinweis Die Ergebnisse von FontMetrics sind bescheiden und mitunter ungenau. Bessere Ergebnisse, etwa über die Ausmaße eines zu zeichnenden Strings, und interessante Zusatzfunktionen bieten FontRenderContext, TextLayout und LineMetrics.
Font font = .; FontRenderContext frc = g.getFontRenderContext(); TextLayout layout = new TextLayout( "Text", font, frc ); Rectangle2D bounds = layout.getBounds(); LineMetrics bietet Angaben wie die nötige Dicke einer Linie beim Unterstreichen und Durchstreichen. Font font = .; FontRenderContext frc =; LineMetrics lm = font.getLineMetrics( str, g.getFontRenderContext() ); |
Einen String unterstreichen
Wir wollen nun stringWidth() und die Metadaten nutzen, um einen unterstrichenen Text darzustellen. Dafür gibt es keine Standardfunktion. Also schreiben wir uns einfach eine Methode, die die Koordinaten sowie den String übergeben bekommt. Die Methode drawUnderlinedString() schreibt mit drawString() die Zeichenkette. drawLine() zeichnet eine Linie unter der Grundlinie mit einer Verschiebung und Dicke, wie sie LineMetrics angibt, und mit der Länge, die das FontMetrics-Objekt für die Zeichenkette liefert.
Listing 15.6 com/javatutor/insel/ui/graphics/DrawUnderlinedString.java, drawUnderlinedString()
public void drawUnderlinedString( Graphics g, int x, int y, String s ) { g.drawString( s, x, y ); FontMetrics fm = g.getFontMetrics(); LineMetrics lm = fm.getLineMetrics( s, g ); g.fillRect( x, y + (int) lm.getUnderlineOffset(), fm.stringWidth(s), (int) lm.getUnderlineThickness() ); }
Natürlich achtet so eine kleine Funktion nicht auf das Aussparen von Buchstaben, die unter der Grundlinie liegen, und so sind die Buchstaben wie »y« oder »q« unten gnadenlos durchgestrichen.





